
/**
 * @file NetworkObsStreams.hpp
 * This class synchronizes rinex observation data streams.
 *
 * shjzhang, 2019/04/30, synchronize the data with time
 */

#ifndef GPSTK_NETWORK_OBS_STREAMS_HPP
#define GPSTK_NETWORK_OBS_STREAMS_HPP

#include <iostream>
#include <string>
#include <list>
#include <map>
#include "DataStructures.hpp"
#include "CommonHeader.hpp"

namespace gpstk
{

      /// @ingroup DataStructures
      //@{


      /** This class synchronizes rinex observation data streams.
       *
       * This class is meant to be used with the GNSS data structures objects
       * found in "DataStructures" class.
       *
       * A typical way to use this class follows:
       *
       * @code
       *    NetworkObsStreams network;
       *
       *    network.addRinexObsFile("NetworkDemo/acor1480.08o");
       *    network.addRinexObsFile("NetworkDemo/madr1480.08o");
       *    network.addRinexObsFile("NetworkDemo/scoa1480.08o");
       *    network.addRinexObsFile("NetworkDemo/sfer1480.08o");
       *
       *    network.actvieSourceSet(SourceIDSet sourceSet);
       *    network.setBeginTime(CommonTime initalTime, double sampleInterval);
       *
       *    sourceRinex gdsMap;
       *    while( network.readEpochData(gdsMap) )
       *    {
       *       // processing code here
       *
       *    }
       *
       * @endcode
       *
       * Each NetworkObsStreams object will handle a RinexObsStream object
       * for every rinex observation file of the network. 
       * 
       * The NetworkObsStreams will synchronize the observation data with  
       * the given initalTime and given sampling interval, instead of the reference
       * data in the previous version.
       *
       * By default, NetworkObsStreams object will skip the observation file failed
       * to be synchronized. When 'NetworkObsStreams::setSynchronizeException(true)'
       * is used, it'll throw a 'SynchronizeException' when faied to synchronize data.
       * Then, you must handle it appropriately.
       *
       */
    class NetworkObsStreams
    {
    public:

         /// Default constructor
        NetworkObsStreams()
        {}


         /// Default destructor
        virtual ~NetworkObsStreams()
        { cleanUp(); }


         /// Add a rinex obs file to the network
         /// @obsFile   Rinex observation file name
        bool addRinexObsFile(const std::string& obsFile);


         /// set rinex index file, which store all the rinex file names 
         /// @rnxIndexFile   Rinex index file name 
        bool setRinexIndexFile(const std::string& rnxIndexFile);


         /// set rinex index file, which store all the rinex file names 
         /// @rnxIndexFile   Rinex index file name 
        void activateSourceSet(SourceIDSet sourceSet);
       

        void setSampleInterval(double sampInterv)
        {
            sampleInterval = sampInterv;
        };

         /// Get epoch data of the network
         /// @epoch     Epoch
         /// @gData     Object hold epoch observation data of the network
        void readEpochData( const CommonTime& epoch,
                            commonHeader& comHeader,
                            sourceRinex& gData );


        Rinex3ObsStream* getRinexObsStream(const SourceID& source)
        { return sourceStreamMap[source]; }

         // Do some clean operation
        virtual void cleanUp();


    protected:

         /// Struct to hold all the data for a observation file
        struct ObsData
        {
            ObsData()
                : obsFile(""), pObsStream(NULL)
            {}
            std::string obsFile;

            SourceID obsSource;

            Rinex3ObsStream* pObsStream;
        };

        AntexReader*  pAntexReader;

         /// Object to hold all the data of the network
        std::list<ObsData> obsDataList;

        std::set<SourceID> allSourceSet;

        std::set<SourceID> activeSourceSet;

        map<SourceID, Triple> sourceMonumentData;
        map<SourceID, Antenna> sourceAntennaData;

        double sampleInterval;

         /// Map to easy access the streams by 'SourceID'
        std::map<SourceID, Rinex3ObsStream*> sourceStreamMap;

    }; // End of class 'NetworkObsStreams'

      //@}


}  // End of namespace gpstk

#endif   // NetworkObsStreams
